/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package hoja4;

import java.util.Scanner;
import java.util.StringTokenizer;

/**
 *
 * @author Nery Giron, Adrian Martinez, Maria Fernanda Martinez, Darwin Rivas
 */
public class Main {

    /**
     * Nombre: main
     * Descripción: lleva a cabo la ejecución del programa
     * Pre: existen todas las clases de las que hace uso
     * Post: acción realizada (en este caso, resultado de una operacion)
     * No hay valor de retorno
     * @param args the command line arguments
     */
    public static void main(String[] args) {
                
        Scanner scanner = new Scanner(System.in); //Ingreso de datos por teclado
        System.out.println("Ingrese el numero de la opcion que desea realizar: \n1. Ingresar operacion\n2. Salir");
        String numero = scanner.nextLine();      
        
        while(numero.equals("1")){
            //Utilizacion del patron de diseño Singleton para asegurar que solo existe una instancia
            Singleton s=Singleton.getInstancia();
            Singleton d=Singleton.getInstancia();
        
            //Utilizacion del Factory para la seleccion de una implementacion de la pila
            StackFactory<String> stackFactory = new StackFactory();
            Stack<String> stack;
            Stack<String> decimal;
        
            s.iniciar(stackFactory.getStack("V",null));
            d.iniciar(stackFactory.getStack("V",null));
            
            String op;
            float num1=0;
            float num2=0;
            float resultado=0;
            
            System.out.println("Ingrese la opcion de Stack que desea usar:\n AL (ArrayList)\n V (Vector)\n L (List)");
            String opcion = scanner.nextLine();
            
            if(opcion.equals("L")){   
                System.out.println("Ingrese la lista que desea usar:\n S (SinglyLinkedList)\n D (DoublyLinkedList)\n C (CircularList)");
                op=scanner.nextLine();
                decimal = stackFactory.getStack(opcion,op); // Pila a usar en las operaciones
                stack = stackFactory.getStack(opcion,op); // Pila que guarda los datos de entrada
            }
            else{
                op=null;
                d.iniciar(stackFactory.getStack(opcion,op)); // Pila a usar en las operaciones
                s.iniciar(stackFactory.getStack(opcion,op)); // Pila que guarda los datos de entrada
                stack=s.obtener();
                decimal=d.obtener();
            }
            
            String cadena;
            String operacion;
            System.out.println("Ingrese operación en formato postfix");
            cadena = scanner.nextLine();
            StringTokenizer st = new StringTokenizer(cadena); // Para separar los datos ingresados por el usuario
            
            // Limpiar la pila y cadena que muestra la operacion
            operacion="";
            stack.clear();
            decimal.clear();


            /*
             * El ciclo while se utiliza para guardar los datos ingresados por el usuario en la pila. 
             */
            while(st.hasMoreTokens())
            {
                stack.push(String.valueOf(st.nextToken())); //Guardar un dato de entrada
                String valor = (String) stack.peek(); //Obtener el dato ingresado
                
                /*
                * La condicion if se utiliza para verificar que el dato ingresado sea numerico; si esto es
                * asi, dicho valor se guarda en la pila para operar. Luego dicho valor es retirado de la pila
                * de entrada. Si el dato no es numerico, se verifica que sea un operador.
                */
                if(stack.isNumeric(valor)){
                    decimal.push(stack.peek());
                    operacion+=stack.pop()+" ";   
                }
                else if(stack.isSymbol(valor)){
                    operacion+=stack.pop()+" ";// Se retira el simbolo de la pila de entrada

                    // Se verifica que hayan al menos dos operandos
                    if(decimal.size()<2){
                        System.out.println("No hay suficientes operandos para \nejecutar la ultima instruccion ingresada");
                        break;
                    }
                    else{
                        //Se verifica que los caracteres sean numeros para operar
                        try{                        
                            if(op == null){
                                num2=Float.parseFloat(String.valueOf(decimal.pop())); // Se obtiene el segundo operando
                                num1=Float.parseFloat(String.valueOf(decimal.pop())); // Se obtiene el primer operando
                            }
                            else if (op.equals("C")){
                                num1=Float.parseFloat(String.valueOf(decimal.pop())); // Se obtiene el primer operando
                                num2=Float.parseFloat(String.valueOf(decimal.pop())); // Se obtiene el segundo operando
                            }
                            else{
                                num2=Float.parseFloat(String.valueOf(decimal.pop())); // Se obtiene el segundo operando
                                num1=Float.parseFloat(String.valueOf(decimal.pop())); // Se obtiene el primer operando
                            }
                            // Se verifica que no sea división por cero
                            if(num2==0&&valor.equals("/")){
                                System.out.println("División por cero");
                                resultado=0; // Se asigna cero al resultado
                            }
                            else
                                resultado=decimal.operate(num1, num2, valor); // Se guarda el resultado de la operacion

                            decimal.push(String.valueOf(resultado)); // El resultado de la operacion se guarda en la pila
                        } catch(NumberFormatException e){
                            System.out.println("Caracteres invalidos, valor asignado a resultado es 0");
                        } catch(NullPointerException e){
                            System.out.println("La lista esta vacia");
                        }
                    }
                }
                else if(op!=null&&op.equals("C")){
                    stack.pop();
                }
                else{
                    System.out.println("Caracteres invalidos, valor asignado a resultado es 0");
                    break;
                }
            }
            //Se despliega el resultado
            System.out.println("Ingreso: "+operacion);
            System.out.println("El resultado es "+resultado+"\n");
            
            //Se solicita al usuario instruccion a realizar
            System.out.println("Ingrese el numero de la opcion que desea realizar: \n1. Ingresar operacion\n2. Salir");
            numero = scanner.nextLine(); 
        }
        if(numero.equals("2")){
            System.out.println("Ha elegido salir.");
        } else {
            System.out.println("Opcion invalida. El programa terminara.");
        }
    }
}

